package com.xuecheng.content.service.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.xuecheng.basic.api.BasicClient;
import com.xuecheng.commons.constants.CourseConstants;
import com.xuecheng.commons.enums.ErrorCode;
import com.xuecheng.commons.model.vo.CategoryVo;
import com.xuecheng.commons.model.vo.ResponseResult;
import com.xuecheng.commons.model.vo.TeachplanVo;
import com.xuecheng.commons.utils.BeanHelper;
import com.xuecheng.content.config.MinioTemplate;
import com.xuecheng.content.domain.CourseBase;
import com.xuecheng.content.domain.CoursePub;
import com.xuecheng.content.mapper.CoursePubMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.CoursePubService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.content.service.TeachplanService;
import com.xuecheng.web.exception.BusinessException;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 课程发布 服务实现类
 * </p>
 *
 * @author itheima
 * @since 2022-12-03
 */
@Service
public class CoursePubServiceImpl extends ServiceImpl<CoursePubMapper, CoursePub> implements CoursePubService {
    @Autowired
    private  TeachplanService teachplanService;
    @Autowired
    private CourseBaseService courseBaseService;
    @Autowired
    private BasicClient basicClient;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    // 课程预览
    @Override
    public Map preview(Long courseBaseId) {
        //查询课程计划 通过id查询课程三级列表
        ResponseResult<TeachplanVo> teachplanVoResponseResult = teachplanService.treeNodes(courseBaseId);
        //获取课程计划对象
        TeachplanVo teachplanVo = teachplanVoResponseResult.getData();
        //准备课程发布对象 通过课程id获取课程基本信息
        CourseBase courseBase = courseBaseService.getById(courseBaseId);
        //将课程基本信息拷贝课程发布
        CoursePub coursePub = BeanHelper.copyProperties(courseBase, CoursePub.class);
        coursePub.setCourseId(courseBaseId);//设置课程id
        //课程分类名称（mt 大分类 st 小分类）
        String mtName = getCategoryId(coursePub.getMt());
        coursePub.setMtName(mtName);
        String stName = getCategoryId(coursePub.getSt());
        coursePub.setMtName(stName);
        //课程计划
        coursePub.setTeachplan(JSON.toJSONString(teachplanVo));
        //课程价格
        coursePub.setPrice(courseBase.getPrice().longValue());
        //发布时间
        coursePub.setCreateDate(new Date());
        //将数据填充到模型
        Map model=new HashMap();
        model.put("coursePub",coursePub);
        model.put("teachplanNode",teachplanVo);
        //返回模型
        return model;


    }
    @Autowired
    private Configuration configuration;
    @Autowired
    private MinioTemplate minioTemplate;
    // 课程发布
    @Transactional
    @Override
    public ResponseResult publish(Long courseBaseId) throws TemplateException, IOException {
        //查询课程信息
        CourseBase courseBase = courseBaseService.getById(courseBaseId);
        //判断课程是否为审核通过状态
        if (!StrUtil.equals(courseBase.getAuditStatus(), CourseConstants.AUDIT_PASTED_STATUS)){
        throw new BusinessException(ErrorCode.MEDIABINDERROR);
        }
        //获取课程发布对象
        Map map = this.preview(courseBaseId);
        //取出map中的课程发布对象
        CoursePub coursePub = (CoursePub) map.get("coursePub");
        //将发布对象保存到数据库
        this.saveOrUpdate(coursePub);
        //更新课程状态为已发布
        courseBase.setAuditStatus(CourseConstants.AUDIT_PUBLISHED_STATUS);
        courseBaseService.updateById(courseBase);
        saveMinio(map,courseBaseId);
        //mq异步更新
        rabbitTemplate.convertAndSend("content-exchange","course.pub",coursePub.getId());
        //返回ok
        return ResponseResult.okResult();
    }

    @Transactional
    //课程下架
    @Override
    public ResponseResult offline(Long courseBaseId) {
        //查询课程信息
        CourseBase courseBase = courseBaseService.getById(courseBaseId);
        //判断课程是否为审核通过状态
        if (!StrUtil.equals(courseBase.getAuditStatus(), CourseConstants.AUDIT_PUBLISHED_STATUS)){
            throw new BusinessException(ErrorCode.MEDIABINDERROR);
        }
        //取出课程发布对象
        this.removeById(courseBaseId);
        //更新课程状态为未提交
        courseBase.setAuditStatus(CourseConstants.AUDIT_UNPAST_STATUS);
        courseBaseService.updateById(courseBase);
        //删除minio
        deleteMinio(courseBaseId);
        //mq异步更新
        rabbitTemplate.convertAndSend("content-exchange","delete",courseBase.getId());
        //返回ok
        return ResponseResult.okResult();
    }

    //多线程执行方法
    @Async
    public void saveMinio(Map map,Long courseBaseId) throws IOException, TemplateException{
        //生成html 保存到minio
        //加载指定模板
        Template template = configuration.getTemplate("learing_article.ftl");
        //模板+数据=输出
        String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
        //将输出文本内容转换为io流进行上传minio
        ByteArrayInputStream inputStream = IoUtil.toStream(content.getBytes());
        //上传
        minioTemplate.uploadHtml(inputStream,courseBaseId+".html");

    }
    //minio删除
    public void deleteMinio(Long courseBaseId){
        minioTemplate.removeHtml("pages/"+courseBaseId+".html");
    }

    // feign查询方法抽取
    private String getCategoryId(String categoryId) {
        ResponseResult<CategoryVo> categoryVoResponseResult = basicClient.findById(categoryId);
        if (categoryVoResponseResult.getCode()!=0) {
            throw new BusinessException(ErrorCode.NOTFOUND);
        }
        CategoryVo categoryVo = categoryVoResponseResult.getData();
        String name = categoryVo.getName();
        return name;
    }
}
